/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022.
 * Description: dying int support for powerpc
 * Author: pengyunlong <pengyunlong@huawei.com>
 * Create: 2022-07-18
 */

#ifndef RTOS_DYING_H
#define RTOS_DYING_H

#include <asm/ioctl.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>

#ifdef CONFIG_RTOS_EARLY_KBOX
#include <linux/cpumask.h>
#include <linux/early_kbox.h>
/*
 * enter exception handling function record lowercase letters of the first
 * letter of function name, exit exception handling function record capital
 * letters of the first letter of function name.
 */
#define ENTER_CRITICAL_EXCEPTION	'c'
#define EXIT_CRITICAL_EXCEPTION		'C'
#define ENTER_MACHINE_CHECK_EXCEPTION	'm'
#define EXIT_MACKINE_CHECK_EXCEPTION	'M'
#define ENTER_DEBUG_EXCEPTION		'd'
#define EXIT_DEBUG_EXCEPTION		'D'
#define ENTER_WATCHDOG_EXCEPTION	'w'
#define EXIT_WATCHDOG_EXCEPTION		'W'
#endif

#define SELF_REFRESH_TIME                              20
#define MAX_DELAY_TIME                                 60000
#define MIN_DELAY_TIME                                 80

#define MPIC_PER_IRQ_OFFSET                            0x20
/* EIVPR,EIDR,EILR is register of pic,more detail please read Reference Manual */
#define MPIC_EIVPR_OFFSET                              0x0
#define MPIC_EIDR_OFFSET                               0x10
#define MPIC_EILR_OFFSET                               0x18

#define MPIC_MSK_BIT                                    31
#define MPIC_POLARITY_BIT                              23
#define MPIC_SENSOR_BIT                                22

#define MPIC_E500_CINT_SET                             0x40000000
#define MPIC_E500_DDR_SELF_REFRESH                     0x80000000

#define MPIC_E500MC_CINT_SET                           0x01
#define MPIC_E500MC_MCP_SET                            0x02
#define MPIC_E500MC_DDR_SELF_REFRESH                   0xf0

#define MPIC_MAX_IRQ_NUM                               0xf
#define MPIC_IOREMAP_SIZE                              0x1000
#define DEFAULT_NMI_IRQ_NUM                            0

#define DDR_CTRL_SET_SELF_REFRESH_MODE                 0x80000000
#ifdef CONFIG_P4080_DS
#define DDR_CTRL_IOREMAP_SIZE                          0x2000
#else
#define DDR_CTRL_IOREMAP_SIZE                          0x1000
#endif

#define IPIC_EDI0_BIT                                  15
#define IPIC_MCP_SIRQ0                                 0x00008000
#define IPIC_IRQ0_ENABLE                               0x80000000
#define DYING_IRQ_CELLS_MAX                            4
#define DYING_BUFFER_SIZE                              256

enum dying_bool {
	DYING_DISABLE             = 0,                     /* disable */
	DYING_ENABLE              = 1,                     /* enable */
};

enum dying_irq_type {
	DYING_IRQ_MCP            = 0,                      /* hardware mcp,p1012 */
	DYING_IRQ_MCP_E500MC     = 1,                      /* setting mcp,e500mc */
	DYING_IRQ_MCP_E300       = 2,                      /* setting mcp,e300 */
	DYING_IRQ_CINT           = 3,                      /* critical interrupt,p1010 */
	DYING_IRQ_MAX
};

struct dying_usr_data {
	unsigned int enable;
	unsigned int delay_time;
};

struct dying_callback {
	struct list_head entry;
	struct rcu_head rcu;
	void (*notify_func)(unsigned int);
};

struct dying_irq {
	unsigned int num;
	unsigned int sense;
	unsigned int type;
	unsigned int information;
};

struct dying_dts_params {
	enum dying_irq_type irq_type;
	struct dying_irq irq;
	unsigned long irq_cfg_offset;
	unsigned int delay_time;
	enum dying_bool ddr_self_refresh;
	unsigned long ddr_cfg_offset;
};

struct dying_int_params {
	enum dying_bool status;
	struct dying_dts_params dts_params;
	char *pic_irq_base_addr;                            /* External Interrupt Configuration Registers */
	unsigned long ddr_ctrl_addr;                        /* ddr control addr */
};
void before_ddr_self_refresh(void);
void set_ddr_self_refresh(void);
bool get_dying_status(void);
void do_ddr_self_refresh(void);
void set_dying_mode(void);
bool get_dying_mode(void);
void dying_from_soft_watchdog(void);
void __noreturn dying_and_reboot_process(struct pt_regs *regs, const char exception_type);
void __noreturn dying_watchdog_proc(struct pt_regs *regs, const char exception_type);

extern atomic_t first_exit_critical;
#endif
